package j.framework.tags.easyui;

import j.framework.query.QueryMetadataManager;
import j.framework.query.core.*;
import j.util.DES;
import j.util.New;
import j.util.StringUtils;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.SimpleTagSupport;
import java.io.IOException;
import java.util.*;

/**
 * 生成easyui的dataGrid或treeGrid，以javascript形式创建
 * Created by junhai on 2015/2/23.
 */
public class DataGridTag extends SimpleTagSupport {
    private String id;
    private String key;//可以是指定的key,也可以是主键
    private String params;//首次加载数据时的额外参数
    private int pageSize;
    private String pageSizeList;
    private boolean initData = false;//是否初始化数据，默认不初始化
    private String toolbarId;
    private boolean noActions = false;//是否显示行操作列
    private String style;
    private String onBeforeSelect;//签名：onBeforeSelect(index,row)
    private String onSelect;//签名：onBeforeSelect(index,row)
    private String onUnselect;//签名：onBeforeSelect(index,row)
    private Boolean multiSelected;//是否允许多选，若为空，则参考查询定义中的设置
    private String onBeforeCheck;//勾选前触发
    private String onCheck;
    private String onUncheck;
    private String onCheckAll;
    private String onUncheckAll;
    private String onLoadSuccess;//datgrid签名：onLoadSuccess(data); treeGrid签名：onLoadSuccess(row,data);
    private int frozenLeftColumns;
    private String title;
    private Integer height;

    @Override
    public void doTag() throws JspException, IOException {
        QueryMetadata qmd = QueryMetadataManager.getQueryMetadata(key);
        if(qmd == null){
            throw new RuntimeException(String.format("查询[%s]不存在，请与系统开发人员联系！",key));
        }
        boolean addCustomFooter = false;
        if(!qmd.isPagingSupported() && StringUtils.isNullOrEmpty(qmd.getFooterClause()) && !qmd.isFooterSupported()){
            addCustomFooter = true;
        }
        StringBuilder s = new StringBuilder();
        String dgId = "$dg_"+id;
        s.append("<table id=\"").append(id).append("\"");
        if(StringUtils.isNotEmpty(style)){
            s.append(" style=\"").append(style).append("\"");
        }
        s.append("></table>\n");
        if(addCustomFooter){
            //需要增加自定义的footer
            s.append("<div id='footer_").append(id).append("' style='padding:5px;'>合计：<b><span id='").append(id).append("_number'>0</span></b> 条数据</div>");
        }
        s.append("<script>\nvar ").append(dgId).append("=$('#").append(id).append("');var isTreeTable=").append(qmd.isTreeTable()).append(";\n");
        StringBuilder json = new StringBuilder("{");
        if(height!=null && height>0){
            json.append("fit:false,height:").append(height);
        }else{
            json.append("fit:true");
        }
        if(StringUtils.isNotEmpty(title)){
            json.append(",title:'").append(title).append("'");
        }
        if(StringUtils.isNotEmpty(toolbarId)){
            json.append(",toolbar:'#").append(toolbarId).append("'");
        }
        String dgGetDataUrl = "/user/req?act=q&key=";
        dgGetDataUrl+= DES.encrypt(key);
        s.append("var ").append(dgId).append("_url=\"").append(dgGetDataUrl).append("\";");
        if(initData){
            if(StringUtils.isNotEmpty(params)){
                if(!params.startsWith("&")){
                    dgGetDataUrl+="&";
                }
                dgGetDataUrl+=params;
            }
            json.append(",url:'").append(dgGetDataUrl).append("'");
        }
        Map<Integer,List<DataGridColumn>> dataGridColumns = new TreeMap<Integer,List<DataGridColumn>>();
        //处理列
        List<DataGridColumn> leftDgColumns = New.list();
        int index = 1;
        if(qmd.hasActions() && !noActions){
            //需要在左侧增加操作列
            DataGridColumn c = new DataGridColumn();
            c.setDisplayOrder(index++);
            c.setFieldKey("actions");
            c.setSuperHeader(false);
            c.setTitle("操作");
            leftDgColumns.add(c);
        }
        boolean isSingleSelect = qmd.isSingleSelect();
        if(multiSelected!=null){
            isSingleSelect = !multiSelected;
        }
        if(!isSingleSelect){
            //允许多选，在最左侧增加选择框
            DataGridColumn c = new DataGridColumn();
            c.setDisplayOrder(index);
            c.setFieldKey("desId");
            c.setSuperHeader(false);
            c.setTitle("选择");
            leftDgColumns.add(c);
        }
        List<DataGridColumn> rightColumns = New.list();
        //除操作列外，左侧需要冻结的列数，若dataGrid定义，则以此为准，若没有定义，则看查询是否定义
        int left = 0;
        if(frozenLeftColumns>0){
            left = frozenLeftColumns;
        }else if(qmd.getFrozenLeftColumns()!=null && qmd.getFrozenLeftColumns()>0){
            left = qmd.getFrozenLeftColumns();
        }
        for(DataGridColumn dgColumn : qmd.getColumns().values()){
            if(left-->0){
                leftDgColumns.add(dgColumn);
                continue;
            }
            rightColumns.add(dgColumn);
        }
        //列容器
        List<List<Map<String,Object>>> columnsList = New.list();
        //先处理冻结的列
        int depth = processDataGridColumns(1,dataGridColumns,leftDgColumns);
        buildDataGridColumns(depth, qmd, dataGridColumns, columnsList);
        //json.append(",frozenColumns:").append(JsonUtils.toJson(columnsList));
        json.append(",frozenColumns:").append(_toColumnsToJson(columnsList));
        columnsList = New.list();
        dataGridColumns.clear();
        depth = processDataGridColumns(1, dataGridColumns,rightColumns);
        buildDataGridColumns(depth, qmd, dataGridColumns, columnsList);
        //json.append(",columns:").append(JsonUtils.toJson(columnsList));
        json.append(",columns:").append(_toColumnsToJson(columnsList));
        //是否单选
        if(isSingleSelect){
            json.append(",singleSelect:true");
        }
        //分页选项
        if(qmd.isPagingSupported()){
            json.append(",pagination:true");
            if(this.pageSize>0){
                json.append(",pageSize:").append(this.pageSize);
            }else if(qmd.getPageSize()!=null && qmd.getPageSize()>0){
                json.append(",pageSize:").append(qmd.getPageSize());
            }
            if(StringUtils.isNotEmpty(this.pageSizeList)){
                json.append(",pageList:[").append(this.pageSizeList).append("]");
            }else if(StringUtils.isNotEmpty(qmd.getPageList())){
                json.append(",pageList:[").append(qmd.getPageList()).append("]");
            }
        }
        //树表选项
        if(qmd.isTreeTable()){
            json.append(",idField:'").append(qmd.getTreeTableIdFieldName()).append("'");
            json.append(",treeField:'").append(qmd.getTreeTableFieldName()).append("'");
        }
        //排序选项
        if(qmd.isMultiColumnSortedSupported()){
            json.append(",multiSort:true");
        }
        json.append(",sortName:'").append(qmd.getDefaultSortNames()).append("'");
        json.append(",sortOrder:'").append(qmd.getDefaultOrders()).append("'");
        //自定义footer
        if(addCustomFooter){
            json.append(",footer:'#footer_").append(id).append("'");
        }
        //让页面加载完后再初始化树表
        s.append("$(function(){");
        //通过标签附加的选项
        if(StringUtils.isNotEmpty(this.onSelect)){
            json.append(",onSelect:").append(this.onSelect);
        }
        if(StringUtils.isNotEmpty(this.onBeforeSelect)){
            json.append(",onBeforeSelect:").append(this.onBeforeSelect);
        }
        if(StringUtils.isNotEmpty(this.onUnselect)){
            json.append(",onUnselect:").append(this.onUnselect);
        }
        //checkbox的事件
        if(!isSingleSelect){
            if(StringUtils.isNotEmpty(this.onBeforeCheck)){
                json.append(",onBeforeCheck:").append(this.onBeforeCheck);
            }
            if(StringUtils.isNotEmpty(this.onCheck)){
                json.append(",onCheck:").append(this.onCheck);
            }
            if(StringUtils.isNotEmpty(this.onUncheck)){
                json.append(",onUncheck:").append(this.onUncheck);
            }
            if(StringUtils.isNotEmpty(this.onCheckAll)){
                json.append(",onCheckAll:").append(this.onCheckAll);
            }
            if(StringUtils.isNotEmpty(this.onUncheckAll)){
                json.append(",onUncheckAll:").append(this.onUncheckAll);
            }
        }
        //onLoadSuccess,需要注意自定义footer
        if(addCustomFooter){
            //有自定义的footer，需要在onLoadSuccess外套层onLoadSuccess，从而调用所配置的函数
            json.append(",onLoadSuccess:").append("function(");
            if(qmd.isTreeTable()){
                json.append("row,");
            }
            json.append("data){$('#").append(id).append("_number').html(data.total);");
            if(StringUtils.isNotEmpty(this.onLoadSuccess)){
                json.append(this.onLoadSuccess).append("(");
                if(qmd.isTreeTable()){
                    json.append("row,");
                }
                json.append("data);");
            }
            json.append("}");
        }else if(StringUtils.isNotEmpty(this.onLoadSuccess)){
            json.append(",onLoadSuccess:").append(this.onLoadSuccess);
        }
        json.append("}");
        if(json.length()>2){
            s.append(dgId).append(".");
            if(qmd.isTreeTable()){
                s.append("treegrid(");
            }else{
                s.append("datagrid(");
            }
            s.append(json.toString());
            s.append(");");
        }
        s.append("});\n</script>\n");
        JspWriter writer = this.getJspContext().getOut();
        writer.write(s.toString());
        writer.flush();
    }

    private void buildDataGridColumns(int depth,QueryMetadata qmd,Map<Integer,List<DataGridColumn>> dataGridColumns,List<List<Map<String,Object>>> columnsList){
        //列集合
        List<Map<String,Object>> columns;
        Map<String,Object> column;
        QueryFieldMetadata qfmd;
        for(Map.Entry<Integer,List<DataGridColumn>> entry : dataGridColumns.entrySet()){
            columns = New.list();
            for(DataGridColumn c : entry.getValue()){
                column = New.map();
                column.put("title",c.getTitle());
                column.put("halign","center");
                if(c.isSuperHeader()){
                    column.put("colspan",c.getSubColumnSize());
                }
                if(c.subColumns==null || c.subColumns.size()==0){
                    if(depth > 1){
                        column.put("rowspan",depth-entry.getKey()+1);
                    }
                    qfmd = qmd.getFieldMetadata(c.getFieldKey());
                    if(qfmd!=null){
                        if(!qfmd.getColumnDataAlign().equals(DataAlign.LEFT)){
                            column.put("align",qfmd.getColumnDataAlign().name());
                        }
                        if(qfmd.getWidth()>10){
                            column.put("width",qfmd.getWidth());
                        }
                        if(qfmd.isUsedFieldNameAsKey()){
                            column.put("field",qfmd.getFieldName());
                        }else{
                            column.put("field",qfmd.getQueryFieldId());
                        }
                        if(qfmd.isSortSupported()){
                            column.put("sortable",true);
                        }
                        if(qfmd.getFormatType().equals(FormatType.JS_FORMAT) && StringUtils.isNotEmpty(qfmd.getFormatOptions())){
                            column.put("formatter",qfmd.getFormatOptions());
                        }
                    }else if(c.getFieldKey().equals("actions")){
                        //这是操作列
                        column.put("field","actions");
                        if(qmd.getActionsColumnWidth()!=null && qmd.getActionsColumnWidth()>0){
                            column.put("width",qmd.getActionsColumnWidth());
                        }
                        column.put("align","center");
                    }else if(c.getFieldKey().equals("desId")){
                        //这是选择列
                        column.put("field","desId");
                        column.put("checkbox",true);
                        column.put("align","center");
                    }
                }
                columns.add(column);
            }
            columnsList.add(columns);
        }
    }

    private int processDataGridColumns(int depth,Map<Integer,List<DataGridColumn>> dataGridColumns,Collection<DataGridColumn> columns){
        List<DataGridColumn> _columns;
        int columnsDepth = depth;
        for(DataGridColumn c : columns){
            _columns = dataGridColumns.get(depth);
            if(null == _columns){
                _columns = New.list();
                dataGridColumns.put(depth,_columns);
            }
            _columns.add(c);
            if(c.isSuperHeader() && c.subColumns.size()>0){
                //有子级
                columnsDepth = processDataGridColumns(depth+1,dataGridColumns,c.subColumns.values());
            }
        }
        return columnsDepth;
    }

    public void setId(String id) {
        this.id = id;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public void setPageSize(int pageSize) {
        this.pageSize = pageSize;
    }

    public void setPageSizeList(String pageSizeList) {
        this.pageSizeList = pageSizeList;
    }

    public void setInitData(boolean initData) {
        this.initData = initData;
    }

    public void setToolbarId(String toolbarId) {
        this.toolbarId = toolbarId;
    }

    public void setParams(String params) {
        this.params = params;
    }

    public void setNoActions(boolean noActions) {
        this.noActions = noActions;
    }

    public void setStyle(String style) {
        this.style = style;
    }

    public void setOnBeforeSelect(String onBeforeSelect) {
        this.onBeforeSelect = onBeforeSelect;
    }

    public void setOnSelect(String onSelect) {
        this.onSelect = onSelect;
    }

    public void setOnUnselect(String onUnselect) {
        this.onUnselect = onUnselect;
    }

    public void setMultiSelected(Boolean multiSelected) {
        this.multiSelected = multiSelected;
    }

    public void setOnBeforeCheck(String onBeforeCheck) {
        this.onBeforeCheck = onBeforeCheck;
    }

    public void setOnCheck(String onCheck) {
        this.onCheck = onCheck;
    }

    public void setOnUncheck(String onUncheck) {
        this.onUncheck = onUncheck;
    }

    public void setOnCheckAll(String onCheckAll) {
        this.onCheckAll = onCheckAll;
    }

    public void setOnUncheckAll(String onUncheckAll) {
        this.onUncheckAll = onUncheckAll;
    }

    public void setOnLoadSuccess(String onLoadSuccess) {
        this.onLoadSuccess = onLoadSuccess;
    }

    public void setFrozenLeftColumns(int frozenLeftColumns) {
        this.frozenLeftColumns = frozenLeftColumns;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public void setHeight(Integer height) {
        this.height = height;
    }

    private static final Set<String> NO_QUOTE_PROPERTIES = New.set();

    static {
        NO_QUOTE_PROPERTIES.add("formatter");
    }

    private String _toColumnsToJson(List<List<Map<String,Object>>> columns){
        StringBuilder s = new StringBuilder("[");
        boolean needQuote = false;
        for(List<Map<String,Object>> list : columns){
            s.append("[");
            for(Map<String,Object> map : list){
                s.append("{");
                for(Map.Entry<String,Object> entry : map.entrySet()){
                    needQuote = false;
                    s.append(entry.getKey()).append(":");
                    if(entry.getValue() instanceof String){
                        needQuote = true;
                    }
                    if(needQuote && NO_QUOTE_PROPERTIES.contains(entry.getKey())){
                        needQuote = false;
                    }
                    if(needQuote){
                        s.append("'");
                    }
                    s.append(entry.getValue());
                    if(needQuote){
                        s.append("'");
                    }
                    s.append(",");
                }
                if(map.size()>0){
                    s.deleteCharAt(s.length()-1);
                }
                s.append("},");
            }
            if(list.size()>0){
                s.deleteCharAt(s.length()-1);
            }
            s.append("],");
        }
        if(columns.size()>0){
            s.deleteCharAt(s.length()-1);
        }
        s.append("]");
        return s.toString();
    }
}
